#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
-------------------------------------------------
   File Name：    mysql_control.py
   Author :       zyq
   CreateDate：   2024/7/22 12:40
   Remark :  数据库的封装
-------------------------------------------------
"""
from pymysql import converters
from pymysql.constants import FIELD_TYPE

from guitesting.common.util.logs import Log

"""
# 调用数据库工具
需要传入的信息
- host='ip',
- port=端口,
- user='用户名',
- password='密码',
- database='连接数据库',     # pymysql只支持单数据库连接
- charset='utf8'
"""

import pymysql
from guitesting.common.file.operation_yaml import ReadYaml

read_yaml = ReadYaml()


class MysqlTool(object):
    def __init__(self, mysql_name=None):
        """
        初始化MySQL连接信息。

        Args:
            mysql_name (str, optional): MySQL数据库的名称。如果为None，则默认从配置文件中获取默认数据库配置。

        Returns:
            None

        """
        conv = converters.conversions
        conv[FIELD_TYPE.NEWDECIMAL] = float
        conv[FIELD_TYPE.DATE] = str
        conv[FIELD_TYPE.TIMESTAMP] = str
        conv[FIELD_TYPE.DATETIME] = str
        conv[FIELD_TYPE.TIME] = str
        read_yaml = ReadYaml()
        # self.conn_info = conn_info
        host = read_yaml.get_every_config(key='global').upper()

        if host == 'PRO':
            mysql_config = read_yaml.get_mysql_config(mysql_name)
        else:
            mysql_config = read_yaml.get_mysql_config()

        self.conn_info = dict(
            host=mysql_config.get('host'),
            user=mysql_config.get('user'),
            password=mysql_config.get('password'),
            database=None,
            port=int(mysql_config.get('port')),
            conv=conv
        )

    def __enter__(self):
        """
        上下文管理器协议中的__enter__方法，在进入with语句块时执行。

        Args:
            无参数。

        Returns:
            self: 返回当前对象实例，以便在with语句块中可以直接访问其属性和方法。

        Raises:
            pymysql.Error: 当数据库连接发生错误时，捕获pymysql.Error异常并打印错误信息，然后重新抛出该异常。

        """
        try:
            # 尝试连接数据库
            self.conn = pymysql.connect(**self.conn_info)
            # 创建一个游标对象
            self.cursor = self.conn.cursor()
            # 返回当前对象实例
            return self

        except TimeoutError as e:
            Log.error(f'数据库链接超时请检查：{e}')
            raise TimeoutError(f'数据库链接超时请检\n{e}')
        except IndentationError as e:
            Log.error('数据库链接用户名不存在请检查')
            raise IndentationError(f"数据库链接用户名不存在请检查\n{e}")
        except pymysql.err.OperationalError as e:
            Log.error(f'用户名或密码错误请检查\n{e}')
            raise pymysql.err.OperationalError('用户名或密码错误请检查')

    def __exit__(self, exc_type, exc_val, exc_tb):
        """
        上下文管理器退出时调用的方法，用于关闭游标对象。

        Args:
            exc_type (Type[BaseException] | None): 异常类型，如果发生异常则为该异常的类型，否则为 None。
            exc_val (BaseException | None): 异常实例，如果发生异常则为该异常的实例，否则为 None。
            exc_tb (TracebackType | None): 异常追踪对象，如果发生异常则为该异常的追踪对象，否则为 None。

        Returns:
            None: 无返回值，该方法用于关闭游标对象。

        """
        self.cursor.close()
        self.conn.close()

    # 增删改的方法（事务：INSERT  UPDATE  DELETE）, pymysql自动开启事务
    def cud_data(self, sql_list):
        """
        执行给定的SQL语句列表。

        Args:
            sql_list (list): 包含SQL语句的列表。

        Returns:
            None: 此函数没有返回值，但会执行SQL语句列表中的每个SQL语句。

        Raises:
            无直接引发异常，但在执行SQL语句时可能会遇到异常，如数据库连接错误、SQL语法错误等。

        """
        for sql in sql_list:
            try:
                # 执行SQL语句
                self.cursor.execute(sql)
            except Exception as e:
                print(f"执行SQL语句失败: {sql}")
                print(f"错误信息: {e}")

    def query(self, sql):
        """
        执行SQL查询并返回查询结果。

        Args:
            sql (str): 要执行的SQL查询语句。

        Returns:
            list: 查询结果列表，每个元素是一个包含查询结果的元组。如果查询失败，则返回None。

        Raises:
            无：此函数不会主动抛出异常，但在执行SQL查询时可能会由于各种原因（如SQL语法错误、数据库连接问题等）引发异常，这些异常会被捕获并打印错误信息。

        """
        try:
            # 执行SQL查询
            self.cursor.execute(sql)
            # 获取查询结果
            return self.cursor.fetchall()
        except Exception as e:
            # 简单的错误处理，实际应用中可能需要更详细的日志记录或错误处理策略
            print(f"Error executing SQL: {e}")
            return None


if __name__ == '__main__':
    # ================================== 供测试使用 ==================================

    with MysqlTool('Mysql_test') as mysql:
        # 查询数据
        mysql.query('select * from ry_user')
